package com.canaan.business.service.bill.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import com.canaan.business.common.enums.inOutStock.InOrderStatusEnum;
import com.canaan.business.common.enums.inOutStock.InStockOrderTypeEnum;
import com.canaan.business.common.enums.inOutStock.OutOrderStatusEnum;
import com.canaan.business.domain.basic.WmsBaseCustomer;
import com.canaan.business.domain.basic.WmsProduct;
import com.canaan.business.domain.bill.SalesRefundBill;
import com.canaan.business.domain.bill.SalesRefundBillDetail;
import com.canaan.business.domain.inOutStock.WmsInStockOrder;
import com.canaan.business.domain.vo.SalesRefundBillExportCheckVo;
import com.canaan.business.domain.vo.SalesRefundBillExportVo;
import com.canaan.business.domain.vo.SalesRefundBillVo;
import com.canaan.business.domain.vo.StockDetailProductVo;
import com.canaan.business.mapper.bill.SalesRefundBillMapper;
import com.canaan.business.service.basic.IWmsBaseCustomerService;
import com.canaan.business.service.basic.IWmsProductService;
import com.canaan.business.service.bill.ISalesRefundBillDetailService;
import com.canaan.business.service.bill.ISalesRefundBillService;
import com.canaan.business.service.inOutStock.IWmsInStockOrderService;
import com.canaan.common.constant.PrefixConstants;
import com.canaan.common.exception.ServiceException;
import com.canaan.common.utils.DateUtils;
import com.canaan.common.utils.SecurityUtils;
import com.canaan.common.utils.StringUtils;
import com.canaan.common.utils.TableNoUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 销售退货单Service业务层处理
 *
 * @author ruoyi
 * @date 2023-01-31
 */
@Service
public class SalesRefundBillServiceImpl implements ISalesRefundBillService {
    @Resource
    private SalesRefundBillMapper salesRefundBillMapper;
    @Resource
    private ISalesRefundBillDetailService salesRefundBillDetailService;
    @Resource
    private IWmsInStockOrderService wmsInStockOrderService;
    @Resource
    private IWmsBaseCustomerService customerService;
    @Resource
    private IWmsProductService productService;


    /**
     * 查询销售退货单
     *
     * @param id 销售退货单主键
     * @return 销售退货单
     */
    @Override
    public SalesRefundBill selectSalesRefundBillById(Long id) {
        return salesRefundBillMapper.selectSalesRefundBillById(id);
    }

    /**
     * 查询销售退货单列表
     *
     * @param salesRefundBill 销售退货单
     * @return 销售退货单
     */
    @Override
    public List<SalesRefundBill> selectSalesRefundBillList(SalesRefundBill salesRefundBill) {
        return salesRefundBillMapper.selectSalesRefundBillList(salesRefundBill);
    }

    /**
     * 新增销售退货单
     *
     * @param salesRefundBill 销售退货单
     * @return 结果
     */
    @Override
    public int insertSalesRefundBill(SalesRefundBill salesRefundBill) {
        if(StringUtils.isBlank(salesRefundBill.getNo())){
            salesRefundBill.setNo(PrefixConstants.RETURN_OF_GOODS+TableNoUtil.getNo(SalesRefundBill.class));
        }
        salesRefundBill.setCreateBy(SecurityUtils.getUsername());
        salesRefundBill.setCreateTime(DateUtils.getNowDate());
        salesRefundBill.setStatus(InOrderStatusEnum.NEW.getCode());
        return salesRefundBillMapper.insertSalesRefundBill(salesRefundBill);
    }

    /**
     * 批量新增销售退货单
     *
     * @param salesRefundBillList 销售退货单列表
     * @return 结果
     */
    @Override
    public int batchInsertSalesRefundBill(List<SalesRefundBill> salesRefundBillList) {
        String username = SecurityUtils.getUsername();
        Date currerTime = DateUtils.getNowDate();
        for (SalesRefundBill salesRefundBill : salesRefundBillList){
            if(StringUtils.isBlank(salesRefundBill.getNo())){
                salesRefundBill.setNo(TableNoUtil.getNo(SalesRefundBill.class));
            }
            salesRefundBill.setCreateBy(username);
            salesRefundBill.setCreateTime(currerTime);
        }
        int insertNum = 0;
        for (int i=0; i<salesRefundBillList.size();) {
            int endIndex = i+500;
            if (endIndex > salesRefundBillList.size()) {
                endIndex = salesRefundBillList.size();
            }
            insertNum = insertNum + salesRefundBillMapper.batchInsertSalesRefundBill(salesRefundBillList.subList(i, endIndex));
            i = endIndex;
        }
        return insertNum;
    }

    /**
     * 修改销售退货单
     *
     * @param salesRefundBill 销售退货单
     * @return 结果
     */
    @Override
    public int updateSalesRefundBill(SalesRefundBill salesRefundBill) {
        salesRefundBill.setUpdateBy(SecurityUtils.getUsername());
        salesRefundBill.setUpdateTime(DateUtils.getNowDate());
        return salesRefundBillMapper.updateSalesRefundBill(salesRefundBill);
    }

    /**
     * 批量修改销售退货单
     *
     * @param salesRefundBillList 销售退货单列表
     * @return 结果
     */
    @Override
    public int batchUpdateSalesRefundBill(List<SalesRefundBill> salesRefundBillList) {
        String username = SecurityUtils.getUsername();
        Date currerTime = DateUtils.getNowDate();
        for (SalesRefundBill salesRefundBill : salesRefundBillList){
            salesRefundBill.setUpdateBy(username);
            salesRefundBill.setUpdateTime(currerTime);
        }
        int updateNum = 0;
        for (int i=0; i<salesRefundBillList.size();) {
            int endIndex = i+500;
            if (endIndex > salesRefundBillList.size()) {
                endIndex = salesRefundBillList.size();
            }
            updateNum = updateNum + salesRefundBillMapper.batchUpdateSalesRefundBill(salesRefundBillList.subList(i, endIndex));
            i = endIndex;
        }
        return updateNum;
    }

    /**
     * 批量删除销售退货单
     *
     * @param ids 需要删除的销售退货单主键集合
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteSalesRefundBillByIds(Long[] ids) {
        SalesRefundBill bill = new SalesRefundBill();
        bill.setIds(CollUtil.toList(ids));
        List<SalesRefundBill> billList = this.selectSalesRefundBillList(bill);
        List<String> nos = billList.stream()
                .filter(e -> InOrderStatusEnum.CANCEL_PENDING_CONFIRMATION.getCode().equals(e.getStatus())
                        || InOrderStatusEnum.ACCOMPLISH.getCode().equals(e.getStatus()))
                .map(SalesRefundBill::getNo).collect(Collectors.toList());
        if(!nos.isEmpty()){
            throw new ServiceException("取消待确认或已完成状态的单据不能删除");
        }
        for (SalesRefundBill salesRefundBill : billList) {
            if(OutOrderStatusEnum.PICKING.getCode().equals(salesRefundBill.getStatus())){
                //校验进行中单据下的出入库单数据
                WmsInStockOrder stockOrder = wmsInStockOrderService.selectWmsInStockOrderByRelOrderNo(salesRefundBill.getNo(), InStockOrderTypeEnum.SALES_REFUND.getCode());
                if(stockOrder != null && stockOrder.getTotalActualQty() > 0){
                    nos.add(salesRefundBill.getNo());
                }
            }
        }
        if(!nos.isEmpty()){
            throw new ServiceException(nos + "单据已有实际入库数量不能删除");
        }
        //入库单和入库单明细删除
        nos = billList.stream().map(SalesRefundBill::getNo).collect(Collectors.toList());
        wmsInStockOrderService.deleteWmsInStockOrderByRelOrderNosAndType(nos, InStockOrderTypeEnum.SALES_REFUND.getCode());
        return salesRefundBillMapper.deleteSalesRefundBillByIds(ids);
    }

    /**
     * 删除销售退货单信息
     *
     * @param id 销售退货单主键
     * @return 结果
     */
    @Override
    public int deleteSalesRefundBillById(Long id) {
        return salesRefundBillMapper.deleteSalesRefundBillById(id);
    }

    /**
     * 查询销售退货单
     *
     * @param no 编号
     * @return 销售退货单
     */
    @Override
    public SalesRefundBill selectSalesRefundBillByNo(String no) {
        return salesRefundBillMapper.selectSalesRefundBillByNo(no);
    }

    /**
     * 批量删除销售退货单
     *
     * @param nos 需要删除的编号集合
     * @return 结果
     */
    @Override
    public int deleteSalesRefundBillByNos(String[] nos) {
        return salesRefundBillMapper.deleteSalesRefundBillByNos(nos);
    }

    /**
     * 删除销售退货单信息
     *
     * @param no 编号
     * @return 结果
     */
    @Override
    public int deleteSalesRefundBillByNo(String no) {
        return salesRefundBillMapper.deleteSalesRefundBillByNo(no);
    }

    @Override
    public int addWithDetail(SalesRefundBillVo salesRefundBillVo) {
        List<SalesRefundBillDetail> salesRefundBillDetails = salesRefundBillVo.getSalesRefundBillDetails();
        SalesRefundBill salesRefundBill = BeanUtil.toBean(salesRefundBillVo, SalesRefundBill.class);
        salesRefundBill.setTotalQty(salesRefundBillDetails.stream().filter(e->e.getQty()!=null).mapToLong(e -> e.getQty()).sum());
        this.insertSalesRefundBill(salesRefundBill);
        if (CollUtil.isNotEmpty(salesRefundBillDetails)) {
            salesRefundBillDetails.forEach(e -> e.setBillNo(salesRefundBill.getNo()));
            salesRefundBillDetailService.batchInsertSalesRefundBillDetail(salesRefundBillDetails);
        }
        return 1;
    }

    @Override
    public List<SalesRefundBillExportVo> exportList(SalesRefundBill salesRefundBill) {
        return salesRefundBillMapper.exportList(salesRefundBill);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int confirm(List<Long> ids) {
        SalesRefundBill bill = new SalesRefundBill();
        bill.setIds(ids);
        List<SalesRefundBill> billList = this.selectSalesRefundBillList(bill);
        billList = billList.stream().filter(e -> InOrderStatusEnum.NEW.getCode().equals(e.getStatus())).collect(Collectors.toList());
        if (billList.isEmpty()) {
            return 0;
        }
        String username = SecurityUtils.getUsername();
        Date date = DateUtils.getNowDate();
        for (SalesRefundBill salesRefundBill : billList) {
            salesRefundBill.setUpdateBy(username);
            salesRefundBill.setUpdateTime(date);
            salesRefundBill.setStatus(OutOrderStatusEnum.PICKING.getCode());
        }
        salesRefundBillMapper.batchUpdateSalesRefundBill(billList);

        //添加入库单
        for (SalesRefundBill salesRefundBill : billList) {
            SalesRefundBillDetail salesRefundBillDetail = new SalesRefundBillDetail();
            salesRefundBillDetail.setBillNo(salesRefundBill.getNo());
            List<SalesRefundBillDetail> adjustInBillDetails = this.salesRefundBillDetailService.selectSalesRefundBillDetailList(salesRefundBillDetail);
            if (CollUtil.isEmpty(adjustInBillDetails)) {
                throw new ServiceException("未维护明细数据");
            }
            List<StockDetailProductVo> stockDetailProductVos = new ArrayList<>();
            for (SalesRefundBillDetail billDetail : adjustInBillDetails) {
                StockDetailProductVo detailProductVo = new StockDetailProductVo();
                detailProductVo.setProductNo(billDetail.getProductNo());
                detailProductVo.setOrderQty(billDetail.getQty());
                stockDetailProductVos.add(detailProductVo);
            }
            wmsInStockOrderService.initBillStockOrder(salesRefundBill.getNo(), InStockOrderTypeEnum.SALES_REFUND.getCode(),salesRefundBill.getCustomerNo(), stockDetailProductVos);
        }


        return billList.size();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int complete(List<Long> ids) {
        SalesRefundBill bill = new SalesRefundBill();
        bill.setIds(ids);
        List<SalesRefundBill> billList = this.selectSalesRefundBillList(bill);
        billList = billList.stream().filter(e -> OutOrderStatusEnum.PICKING.getCode().equals(e.getStatus())).collect(Collectors.toList());
        if (billList.isEmpty()) {
            throw  new ServiceException("单据状态不是"+OutOrderStatusEnum.PICKING.getMessage());
        }
        String username = SecurityUtils.getUsername();
        Date date = DateUtils.getNowDate();
        for (SalesRefundBill salesRefundBill : billList) {
            WmsInStockOrder wmsInStockOrder = wmsInStockOrderService.selectWmsInStockOrderByRelOrderNo(salesRefundBill.getNo(), InStockOrderTypeEnum.SALES_REFUND.getCode());
            if (wmsInStockOrder != null && InOrderStatusEnum.ACCOMPLISH.getCode().equals(wmsInStockOrder.getOrderStatus())) {
                salesRefundBill.setUpdateBy(username);
                salesRefundBill.setUpdateTime(date);
                salesRefundBill.setCompleteTime(date);
                salesRefundBill.setStatus(InOrderStatusEnum.ACCOMPLISH.getCode());
            } else {
                throw new ServiceException("入库单未完成，关联编号：" + salesRefundBill.getNo());
            }
        }
        salesRefundBillMapper.batchUpdateSalesRefundBill(billList);
        return 1;
    }

    @Override
    public List<String> importExcel(List<SalesRefundBillExportVo> list) {
        List<String> errList = new ArrayList<>();
        Map<String, List<SalesRefundBillExportVo>> groupMap = list.stream().collect(Collectors.groupingBy(e->e.getCustomerName()+":"+e.getSalesOrderNo()));
        Set<String> groupKeys = groupMap.keySet();
        for (String groupKey : groupKeys) {
            String[] split = groupKey.split(":");
            String customerName = split[0];
            String salesOrderNo = split[1];
            List<SalesRefundBillExportVo> salesRefundBillExportVos = groupMap.get(groupKey);
            WmsBaseCustomer wmsBaseCustomer = customerService.selectWmsBaseCustomerByName(customerName);
            if (wmsBaseCustomer == null) {
                errList.add("无效客户名称：" + customerName);
                continue;
            }
            SalesRefundBill salesRefundBill = new SalesRefundBill();
            salesRefundBill.setCustomerNo(wmsBaseCustomer.getNo());
            salesRefundBill.setCustomerName(wmsBaseCustomer.getName());
            salesRefundBill.setSalesOrderNo(salesOrderNo);
            salesRefundBill.setTotalQty(salesRefundBillExportVos.stream().filter(e->e.getQty()!=null).mapToLong(e -> e.getQty()).sum());
            this.insertSalesRefundBill(salesRefundBill);

            List<SalesRefundBillDetail> details = new ArrayList<>();
            for (SalesRefundBillExportVo salesRefundBillExportVo : salesRefundBillExportVos) {
                SalesRefundBillDetail salesRefundBillDetail = new SalesRefundBillDetail();
                salesRefundBillDetail.setBillNo(salesRefundBillExportVo.getNo());
                salesRefundBillDetail.setQty(salesRefundBillExportVo.getQty());
                salesRefundBillDetail.setProductNo(salesRefundBillExportVo.getProductNo());
                WmsProduct wmsProduct = productService.selectWmsProductByProductNo(salesRefundBillExportVo.getProductNo());
                if (wmsProduct == null) {
                    errList.add("无效物料编码：" + wmsProduct.getProductNo());
                    continue;
                }
                salesRefundBillDetail.setProductName(wmsProduct.getProductName());
                salesRefundBillDetail.setProductUnit(wmsProduct.getCompany());
                details.add(salesRefundBillDetail);
            }
            if (CollUtil.isNotEmpty(details)) {
                salesRefundBillDetailService.batchInsertSalesRefundBillDetail(details);
            }
        }
        return errList;
    }

    @Override
    @Transactional
    public int cancel(List<Long> ids) {
        SalesRefundBill bill = new SalesRefundBill();
        bill.setIds(ids);
        List<SalesRefundBill> billList = this.selectSalesRefundBillList(bill);
        billList = billList.stream().filter(e -> InOrderStatusEnum.NEW.getCode().equals(e.getStatus())
                || InOrderStatusEnum.PICKING.getCode().equals(e.getStatus())).collect(Collectors.toList());
        if (billList.isEmpty()) {
            return 0;
        }
        for (SalesRefundBill salesRefundBill : billList) {
            WmsInStockOrder wmsInStockOrder = wmsInStockOrderService.selectWmsInStockOrderByRelOrderNo(salesRefundBill.getNo(), InStockOrderTypeEnum.SALES_REFUND.getCode());
            if (wmsInStockOrder!=null) {
                if ( wmsInStockOrder.getTotalActualQty() > 0){
                    throw new ServiceException("已入库不允许取消，单号：" + salesRefundBill.getNo());
                }
                wmsInStockOrder.setOrderStatus(InOrderStatusEnum.CANCEL.getCode());
                this.wmsInStockOrderService.updateWmsInStockOrder(wmsInStockOrder);
            }
        }
        billList.stream().forEach(e -> e.setStatus(InOrderStatusEnum.CANCEL.getCode()));
        this.batchUpdateSalesRefundBill(billList);
        return billList.size();
    }

    @Override
    public List<SalesRefundBillExportCheckVo> exportCheckList(SalesRefundBill salesRefundBill) {
        return salesRefundBillMapper.exportCheckList(salesRefundBill);
    }

    /**
     * 确认取消
     * @param bill 单据信息
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int confirmCancel(SalesRefundBill bill) {
        bill = this.selectSalesRefundBillById(bill.getId());
        if(bill == null){
            throw new ServiceException("单据不存在");
        }else if(!InOrderStatusEnum.CANCEL_PENDING_CONFIRMATION.getCode().equals(bill.getStatus())){
            throw new ServiceException("该状态不是取消待确认，无法确认取消");
        }

        WmsInStockOrder stockOrder = wmsInStockOrderService.selectWmsInStockOrderByRelOrderNo(bill.getNo(), InStockOrderTypeEnum.SALES_REFUND.getCode());
        if(stockOrder != null){
            stockOrder.setOrderStatus(InOrderStatusEnum.CANCEL.getCode());
            wmsInStockOrderService.updateWmsInStockOrder(stockOrder);
        }
        bill.setStatus(InOrderStatusEnum.CANCEL.getCode());
        return this.updateSalesRefundBill(bill);
    }
}
